/*
 * Copyright (c) 2021 KaiHong Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "ohos_types.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_wifi.h"
#include "lwip/sockets.h"
#include "rtc_if.h"

#include "oc_mqtt.h"
#include "aht20.h"
#include "rtc_base.h"
#define MSGQUEUE_OBJECTS 16  // number of Message Queue Objects
#define IOT_IO_NAME_GPIO_5 5 // for oled button A

typedef struct
{ // object data type
    char *Buf;
    uint8_t Idx;
} MSGQUEUE_OBJ_t;

MSGQUEUE_OBJ_t msg;
osMessageQueueId_t mid_MsgQueue; // message queue id
uint8 buttonPressed = 0;

// temp
#define CLIENT_ID "612cc2572cce4f028621af08_TestWeek_0_0_2021083011"
#define USERNAME "612cc2572cce4f028621af08_TestWeek"
#define PASSWORD "65da9ab7e8b05db36fad7ed21cfe416646f74e00882bd4846ba23aafcb8fb949"

#if 0     
"park"
#define CLIENT_ID "6125e00d0ad1ed0286647065_test20210825111111111_0_0_2021082506"
#define USERNAME "6125e00d0ad1ed0286647065_test20210825111111111"
#define PASSWORD "80c5b63880924315863d80f84035895cb0d3a1074fd2a4e1cb4aba1855b4cc88"
#endif

typedef enum
{
    en_msg_cmd = 0,
    en_msg_report,
    en_msg_shadow,
} en_msg_type_t;

typedef struct
{
    char *request_id;
    char *payload;
    size_t len;
} cmd_t;

typedef struct
{
    uint32 Temperature1; //温度
    uint32 Temperature2; //温度
    uint32 Temperature3; //温度
    uint32 Temperature4; //温度
    uint32 Temperature5; //温度
    uint32 Temperature6; //温度
    uint32 Temperature0; //温度
    uint8 wday;
} report_t;

typedef struct
{
    en_msg_type_t msg_type;
    union
    {
        cmd_t cmd;
        report_t report;
    } msg;
} app_msg_t;

uint8 weekDay;

static void deal_report_msg(report_t *report)
{
    char key1[13] = {0};
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t Temperature; //温度

    service.event_time = NULL;
    service.service_id = "wktmp";
    service.service_property = &Temperature;
    service.nxt = NULL;

    if (report->Temperature0 > 0)
    {
        Temperature.key = "Tempday0";
        Temperature.value = &report->Temperature0;
    }
    else if (report->Temperature1 > 0)
    {
        Temperature.key = "Tempday1";
        Temperature.value = &report->Temperature1;
    }
    else if (report->Temperature2 > 0)
    {
        Temperature.key = "Tempday2";
        Temperature.value = &report->Temperature2;
    }
    else if (report->Temperature3 > 0)
    {
        Temperature.key = "Tempday3";
        Temperature.value = &report->Temperature3;
    }
    else if (report->Temperature4 > 0)
    {
        Temperature.key = "Tempday4";
        Temperature.value = &report->Temperature4;
    }
    else if (report->Temperature5 > 0)
    {
        Temperature.key = "Tempday5";
        Temperature.value = &report->Temperature5;
    }
    else if (report->Temperature6 > 0)
    {
        Temperature.key = "Tempday6";
        Temperature.value = &report->Temperature6;
    }
    Temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    Temperature.nxt = NULL;

    oc_mqtt_profile_propertyreport(USERNAME, &service);
    return;
}

static void getShadow(void)
{
    int ret;
    oc_mqtt_profile_shadowget_t payload;
    payload.object_device_id = USERNAME;
    char request[10] = {0};
    sprintf(request, "R%d", rand()%10000);
    payload.request_id = request ;
    payload.service_id = "wktmp";
    ret = oc_mqtt_profile_getshadow(CLIENT_ID, &payload);
    //printf("getShadow  ret %d--\n");
}

void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    app_msg_t *app_msg;

    int ret = 0;
    app_msg = malloc(sizeof(app_msg_t));
    app_msg->msg_type = en_msg_shadow;
    app_msg->msg.cmd.payload = (char *)recv_data;
    app_msg->msg.cmd.len = recv_size;

    ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U);
    if (ret != 0)
    {
        free(recv_data);
    }
    *resp_data = NULL;
    *resp_size = 0;
}

///< COMMAND DEAL
#include <cJSON.h>

#define TAG "}]}"
#define VERSION "version"

static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_paras;
    cJSON *obj_para;
    
    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;
    char respons[230]={0};
    memcpy(respons, cmd->payload, 217);
    //printf("deal_cmd_msg respons:\n|%s|\n", respons);
    respons[217]='}';
    respons[218]=']';
    respons[219]='}';
    respons[220]='\0';
    //printf("deal_cmd_msg 2 respons:\n|%s|\n", respons);

    obj_root = cJSON_Parse(respons);
    if (NULL == obj_root)
    {
        printf("----cJSON_Parse error-\n");
        goto do_err;
    }
    
    obj_paras = cJSON_GetObjectItem(obj_root, "shadow");
    obj_paras = cJSON_GetArrayItem(obj_paras, 0);
    if (NULL == obj_paras)
    {
        printf("----cJSON_GetObjectItem 1 error-\n");
        goto do_err;
    }
    cJSON *items = cJSON_GetObjectItem(obj_paras, "reported");
    cJSON *item = NULL;
    if (strcmp(items->string, "reported") == 0)
    {
        items = cJSON_GetObjectItem(items, "properties");
        item = cJSON_GetObjectItem(items, "Tempday0");        
        if (NULL == item)
        {
            printf("----cJSON_GetObjectItem Tempday0 error-\n");
            goto do_err;
        }
       
        item = cJSON_GetObjectItem(items, "Tempday1");
        if (NULL == item)
        {
            printf("----cJSON_GetObjectItem Tempday 1 error-\n");
            goto do_err;
        }
    }

    do_err:
       return;
       
}
uint8 wifiSuccess = 0;
static int task_main_entry(void)
{
    app_msg_t *app_msg;

    BOARD_ConnectWifi("test", "11111111");
    wifiSuccess = 1;
    device_info_init(CLIENT_ID, USERNAME, PASSWORD);
    oc_mqtt_init();
    oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);
    getShadow();
    while (1)
    {
        if (buttonPressed == 1)
        {
            break;
            buttonPressed = 0;
        }
        osDelay(100);
    }

    int i = 0;
    while (1)
    {
        app_msg = NULL;
        (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U);
        if (NULL != app_msg)
        {
            switch (app_msg->msg_type)
            {
            // case en_msg_cmd:
            //     deal_cmd_msg(&app_msg->msg.cmd);
            //     break;
            case en_msg_report:
                deal_report_msg(&app_msg->msg.report);
                break;
            case en_msg_shadow:
                deal_cmd_msg(&app_msg->msg.cmd);
            default:
                break;
            }
            free(app_msg);
            i++;
            if (i > 30)
                break;
        }
    }
    return 0;
}
static void setAppmsg(app_msg_t *app_msg, float temp)
{
    uint32 temp2 = 0;
    temp2 = (int)temp;
    app_msg->msg.report.wday = weekDay;   
    if (app_msg->msg.report.wday == 0)
        app_msg->msg.report.Temperature0 = temp2;
    else if (app_msg->msg.report.wday == 1)
        app_msg->msg.report.Temperature1 = temp2;
    else if (app_msg->msg.report.wday == 2)
        app_msg->msg.report.Temperature2 = temp2;
    else if (app_msg->msg.report.wday == 3)
        app_msg->msg.report.Temperature3 = temp2;
    else if (app_msg->msg.report.wday == 4)
        app_msg->msg.report.Temperature4 = temp2;
    else if (app_msg->msg.report.wday == 5)
        app_msg->msg.report.Temperature5 = temp2;
    else if (app_msg->msg.report.wday == 6)
        app_msg->msg.report.Temperature6 = temp2;
}
static int task_sensor_entry(void)
{
    app_msg_t *app_msg;
    AHT20_TYPE data;
    uint32 retval = 0;

    while (IOT_SUCCESS != AHT20_Calibrate())
    {
        printf("AHT20 sensor init failed!\r\n");
        usleep(1000);
    }

    while (1)
    {
        retval = AHT20_StartMeasure();
        if (retval != IOT_SUCCESS)
        {
            printf("trigger measure failed!\r\n");
        }

        retval = AHT20_GetMeasureResult(&data.Temperature, &data.Humidity);
        if (retval != IOT_SUCCESS)
        {
            printf("get humidity data failed!\r\n");
        }

        app_msg = malloc(sizeof(app_msg_t));
        if (NULL != app_msg)
        {
            app_msg->msg_type = en_msg_report;
            memset(&app_msg->msg.report, 0x00, sizeof(report_t));
            setAppmsg(app_msg, data.Temperature);
            if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))
            {
                free(app_msg);
            }
        }
        osDelay(2000);
    }
    return 0;
}
static void OnButtonAPressed(char *arg)
{
    (void)arg;
    IoTGpioUnregisterIsrFunc(IOT_IO_NAME_GPIO_5);

    buttonPressed = 1;

    IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_5, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW,
                           OnButtonAPressed, NULL);
}

#define DEST_PORT 8888

//#define DEST_IP "210.72.145.8"
#define DEST_IP "119.3.7.164"
char send_buf[20] = {0};
char recv_buf[30] = {0};

static void TcpClientTest(void)
{
    ssize_t retval = 0;
    uint64_t seconds;

    while (1)
    {
        if (!wifiSuccess)
            break;
        osDelay(100);
    }
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;        // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(DEST_PORT); // 端口号，从主机字节序转为网络字节序
    if (inet_pton(AF_INET, DEST_IP, &serverAddr.sin_addr) <= 0)
    { // 将主机IP地址从“点分十进制”字符串 转化为 标准格式（32位整数）
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接，连接成功会返回0 ，失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", DEST_IP);

    strcat(send_buf, "GetDay");
    //strcat(send_buf,"Connection: close\r\n");

    // 建立连接成功之后，这个TCP socket描述符 —— sockfd 就具有了 “连接状态”，发送、接收 对端都是 connect 参数指定的目标主机和端口
    retval = send(sockfd, send_buf, sizeof(send_buf), 0);
    if (retval < 0)
    {
        printf("send request failed!\r\n");
        goto do_cleanup;
    }
    retval = recv(sockfd, &recv_buf, sizeof(recv_buf), 0);
    if (retval <= 0)
    {
        printf("send response from server failed or done, %ld!\r\n", retval);
        goto do_cleanup;
    }

    recv_buf[retval] = '\0';
    weekDay = atoi(recv_buf);

do_cleanup:
    close(sockfd);
}
static void OC_Demo(void)
{

    IoTI2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);

    IoTGpioInit(IOT_IO_NAME_GPIO_5); // oled button  按键A
    IoTGpioSetDir(IOT_IO_NAME_GPIO_5, IOT_GPIO_DIR_IN);

    IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_5, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, OnButtonAPressed, NULL);

    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 10, NULL);
    if (mid_MsgQueue == NULL)
    {
        printf("Falied to create Message Queue!\n");
    }

    osThreadAttr_t attr;

    attr.name = "task_main_entry";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 24;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_main_entry!\n");
    }

    attr.stack_size = 4096;
    attr.priority = 24;
    attr.name = "TcpClientTest";
    if (osThreadNew((osThreadFunc_t)TcpClientTest, NULL, &attr) == NULL)
    {
        printf("Falied to create SntpInit!\n");
    }

    attr.stack_size = 2048;
    attr.priority = 23;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_sensor_entry!\n");
    }
}

APP_FEATURE_INIT(OC_Demo);